use serde::{Deserialize, Serialize};
use std::path::PathBuf;
use std::fs;
use anyhow::Result;

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct PlayerConfig {
    // 播放器设置
    pub default_volume: f32,
    pub remember_position: bool,
    pub auto_play: bool,
    pub hardware_acceleration: bool,

    // 视频设置
    pub preferred_video_decoder: String,
    pub video_buffer_size: usize,
    pub video_frame_queue_size: usize,

    // 音频设置
    pub preferred_audio_decoder: String,
    pub audio_buffer_size: usize,
    pub audio_frame_queue_size: usize,

    // 性能设置
    pub thread_count: usize,
    pub max_memory_usage: usize,  // MB
}

impl Default for PlayerConfig {
    fn default() -> Self {
        Self {
            default_volume: 1.0,
            remember_position: true,
            auto_play: true,
            hardware_acceleration: true,
            preferred_video_decoder: "auto".to_string(),
            video_buffer_size: 8 * 1024 * 1024,  // 8MB
            video_frame_queue_size: 30,
            preferred_audio_decoder: "auto".to_string(),
            audio_buffer_size: 2 * 1024 * 1024,  // 2MB
            audio_frame_queue_size: 50,
            thread_count: num_cpus::get(),
            max_memory_usage: 512,  // 512MB
        }
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PlaybackHistory {
    pub path: String,
    pub position: f64,
    pub last_played: chrono::DateTime<chrono::Utc>,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct Config {
    pub player: PlayerConfig,
    pub history: Vec<PlaybackHistory>,
    pub version: String,
}

impl Default for Config {
    fn default() -> Self {
        Self {
            player: PlayerConfig::default(),
            history: Vec::new(),
            version: env!("CARGO_PKG_VERSION").to_string(),
        }
    }
}

impl Config {
    pub fn load() -> Result<Self> {
        let config_path = Self::get_config_path()?;
        
        if !config_path.exists() {
            let config = Config::default();
            config.save()?;
            return Ok(config);
        }

        let content = fs::read_to_string(&config_path)?;
        let config: Config = serde_json::from_str(&content)?;
        Ok(config)
    }

    pub fn save(&self) -> Result<()> {
        let config_path = Self::get_config_path()?;
        
        // 确保配置目录存在
        if let Some(parent) = config_path.parent() {
            fs::create_dir_all(parent)?;
        }

        let content = serde_json::to_string_pretty(self)?;
        fs::write(&config_path, content)?;
        Ok(())
    }

    pub fn add_to_history(&mut self, path: String, position: f64) {
        let now = chrono::Utc::now();
        
        // 更新现有记录或添加新记录
        if let Some(entry) = self.history.iter_mut().find(|h| h.path == path) {
            entry.position = position;
            entry.last_played = now;
        } else {
            self.history.push(PlaybackHistory {
                path,
                position,
                last_played: now,
            });
        }

        // 保持历史记录在合理范围内
        if self.history.len() > 100 {
            self.history.sort_by(|a, b| b.last_played.cmp(&a.last_played));
            self.history.truncate(100);
        }
    }

    pub fn get_last_position(&self, path: &str) -> Option<f64> {
        self.history
            .iter()
            .find(|h| h.path == path)
            .map(|h| h.position)
    }

    fn get_config_path() -> Result<PathBuf> {
        let config_dir = dirs::config_dir()
            .ok_or_else(|| anyhow::anyhow!("Could not determine config directory"))?
            .join("axplayer");
        
        Ok(config_dir.join("config.json"))
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use tempfile::tempdir;
    use std::env;

    #[test]
    fn test_config_default() {
        let config = Config::default();
        assert_eq!(config.player.default_volume, 1.0);
        assert!(config.history.is_empty());
    }

    #[test]
    fn test_config_save_load() {
        let dir = tempdir().unwrap();
        env::set_var("HOME", dir.path());

        let mut config = Config::default();
        config.add_to_history("test.mp4".to_string(), 42.0);
        
        config.save().unwrap();
        let loaded = Config::load().unwrap();
        
        assert_eq!(loaded.history.len(), 1);
        assert_eq!(loaded.history[0].path, "test.mp4");
        assert_eq!(loaded.history[0].position, 42.0);
    }
} 